package cn.ztelovecly.springboot.framework.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 与List类型相关的工具类。<br/>
 * 测试方法
 */
public class ListUtil<T> {
	/**
	 * 将一个列表中的一个Long型字段与 另一个Long列表进行匹配，返回满足条件的结果。<br/>
	 * 例如：list 包含一列名称为“id”的Long型字段,包含五条数据，id字段的值分别为1，2，3，4，5<br/>
	 *      fieldName 指定为“id”<br/>
	 *      ids为一个包含1，2，3三条数据的Long型数组<br/><br/>
	 *
	 *      则该方法会返回list中id为1，2，3的三条数据。<br/>
	 * @param list          源列表
	 * @param fieldName     列表中需要匹配的字段名
	 * @param ids           ID列表
	 * @return              指定列的数据在ID列表中存在的数据列表
	 */
	public List<T> matchLongList(List<T> list, String fieldName, List<Long> ids) throws NoSuchFieldException, NoSuchMethodException {
		if(ids == null) {
			throw new NullPointerException("要匹配的ID列表不能为空");
		}
		if(ids.size() == 0) {
			System.out.println(this.getClass().getName() + "：matchLongList（List,String,List） 传入的ID列表没有值");
			return new ArrayList<>();
		}

		//把所有的结果加入Map中
		Map<Long, T> map = getMap(list, fieldName);

		List<T> result = new ArrayList<>();
		for(Long id : ids) {
			T temp = map.get(id);
			if(temp != null) {
				result.add(temp);
			}
		}
		return result;
	}
	public List<T> matchLongList(Map<Long, T> map, List<Long> ids) throws NoSuchFieldException, NoSuchMethodException {
		List<T> result = new ArrayList<>();
		for(Long id : ids) {
			T temp = map.get(id);
			if(temp != null) {
				result.add(temp);
			}
		}
		return result;
	}

	/**
	 * 转换一个列表为Map,可以指定key.必须为Long型.<br/>
	 *
	 * <b>不建议使用.建议使用 {@link MapUtil#transferList}方法.</b>
	 *
	 * @param list         要转换的列表
	 * @param fieldName    key对应的属性名称
	 * @see cn.ztelovecly.springboot.framework.util.MapUtil
	 * @return             Map
	 * @throws NoSuchFieldException     未找到指定的属性
	 * @throws NoSuchMethodException    未找到指定属性的getter方法
	 */
	@Deprecated
	public Map<Long, T> getMap(List<T> list, String fieldName) throws NoSuchFieldException, NoSuchMethodException {
		if(list == null) {
			throw new NullPointerException("传入的对象列表<list>不能为空");
		}
		if(fieldName == null || fieldName.equals("")) {
			throw new NullPointerException("要匹配的字段名不能为空");
		}
		if(list.size() == 0) {
			System.out.println(this.getClass().getName() + "：getMap（List,String,List） 传入的对象列表没有值");
			return new HashMap<>();
		}

		T t = list.get(0);
		Class clazz = t.getClass();
		Method method ;
		try {
			method = clazz.getMethod("get" + StringUtil.upperFirstWord(fieldName));
		} catch (NoSuchMethodException e) {
			throw new NoSuchMethodException("未找到为" + fieldName + "定义的getter方法。" +
					"请检查" + clazz.getName() + "类中是否有 get" + StringUtil.upperFirstWord(fieldName) + "方法");
		}

		//把所有的结果加入Map中
		Map<Long, T> map = new HashMap<>();
		for(T temp : list) {
			Long id = null;
			try {
				id = (Long) method.invoke(temp);
			} catch (IllegalAccessException | InvocationTargetException e) {
				e.printStackTrace();
			}
			map.put(id, temp);
		}
		return map;
	}

	/**
	 * 转换一个列表为Map,可以指定key.<br/>
	 *
	 * <b>建议使用MapUtil中的getHashMap.</b>
	 *
	 * @param list         要转换的列表
	 * @param fieldName    key对应的属性名称
	 * @return             Map
	 * @throws NoSuchFieldException     未找到指定的属性
	 * @throws NoSuchMethodException    未找到指定属性的getter方法
	 */
	@Deprecated
	public Map<Object, T> getHashMap(List<T> list, String fieldName) throws NoSuchFieldException, NoSuchMethodException {
		if(list == null) {
			throw new NullPointerException("传入的对象列表<list>不能为空");
		}
		if(fieldName == null || fieldName.equals("")) {
			throw new NullPointerException("要匹配的字段名不能为空");
		}
		if(list.size() == 0) {
			System.out.println(this.getClass().getName() + "：getHashMap（List,String,List） 传入的对象列表没有值");
			return new HashMap<>();
		}

		T t = list.get(0);
		Class clazz = t.getClass();
		Method method ;
		try {
			method = clazz.getMethod("get" + StringUtil.upperFirstWord(fieldName));
		} catch (NoSuchMethodException e) {
			throw new NoSuchMethodException("未找到为" + fieldName + "定义的getter方法。" +
					"请检查" + clazz.getName() + "类中是否有 get" + StringUtil.upperFirstWord(fieldName) + "方法");
		}

		//把所有的结果加入Map中
		Map<Object, T> map = new HashMap<>();
		for(T temp : list) {
			Object id = null;
			try {
				id = method.invoke(temp);
			} catch (IllegalAccessException | InvocationTargetException e) {
				e.printStackTrace();
			}
			map.put(id, temp);
		}
		return map;
	}


	/**
	 * 获取一个新的列表,它的内容为A-B
	 *
	 * @param entireList 列表A
	 * @param minusList  列表B
	 * @return 一个新的列表, 内容为A-B
	 */
	public List<T> removeExist(List<T> entireList, List<T> minusList) {
		if(entireList == null ) {
			return new ArrayList<>();
		}
		if (entireList.size() == 0 || minusList == null || minusList.size() == 0 ) {
			return entireList;
		}
		List<T> result = new ArrayList<>();
		for (T entire : entireList) {
			if( ! minusList.contains(entire)) {
				result.add(entire);
			}
		}
		return result;
	}

	/**
	 * 根据两个id列表，比较出以下3种列表：
	 * 1、需要删除的Id列表
	 * 2、需要更新的Id列表
	 * 3、需要插入的Id列表
	 * 使用Map<String, List<Long>>接收
	 * 提取方法：
	 * 1、需要删除的Id列表:.get("delete")
	 * 2、需要更新的Id列表:.get("update")
	 * 3、需要插入的Id列表:.get("insert")
	 * @param oldIds 原来的id列表
	 * @param newIds 新的id列表
	 * @return
	 */
	public Map<String, List<Long>> compareWithLists(List<Long> oldIds, List<Long> newIds) {
		Map<String, List<Long>> result = new HashMap<>();
		//需要删除的值的Ids
		List<Long> deleteIds = new ArrayList<>();
		//需要更新的值的Ids
		List<Long> updateIds = new ArrayList<>();
		//需要插入的值的Ids
		List<Long> insertIds = new ArrayList<>();

		for (Long id : oldIds){
			//新Ids中不包含这个Id，则删除
			//否则更新
			if (!newIds.contains(id)){
				deleteIds.add(id);
			} else {
				updateIds.add(id);
			}
		}
		//旧Id列表不包含，则为添加
		for (Long id : newIds) {
			if (!oldIds.contains(id)){
				insertIds.add(id);
			}
		}

		result.put("delete", deleteIds);
		result.put("update", updateIds);
		result.put("insert", insertIds);
		return result;
	}
}
